package com.ak.game.netty;

import cn.hutool.core.util.ObjectUtil;
import com.ak.game.exception.ServiceException;
import com.ak.game.factory.GameFactory;
import com.ak.game.handler.GameAbstractHandler;
import com.ak.game.util.AjaxResult;
import com.ak.game.util.CommonUtil;
import com.alibaba.fastjson2.JSON;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Slf4j
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     * 重写SimpleChannelInboundHandler的channelRead0方法，处理接收到的消息
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *            belongs to
     * @param msg the message to handle
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        String text = msg.text();
        // 异步验证game参数
        CompletableFuture<Map<String, Object>> gameIdFuture = CommonUtil.fetchAndVerifyEntity(
                text,
                k -> {
                    HashMap<String, Object> hashMap = JSON.parseObject(k, HashMap.class);
                    try {
                        StringUtil.isNullOrEmpty(((HashMap<String, Object>) hashMap.get("game")).get("id").toString());
                    } catch (Exception e) {
                        throw new ServiceException("10000");
                    }
                    return hashMap;
                },
                "10000"
        );
        // 异步验证获取GameAbstractHandler类
        CompletableFuture<GameAbstractHandler> gameHandlerCompletableFuture = gameIdFuture.thenCompose(
                t -> CommonUtil.fetchAndVerifyEntity(((HashMap<String, Object>) t.get("game")).get("id").toString(), GameFactory::getInvokeStrategy, "10000"));
        Map<String, Object> map;
        GameAbstractHandler gameAbstractHandler;
        try {
            map = gameIdFuture.get();
            gameAbstractHandler = gameHandlerCompletableFuture.get();
        } catch (Exception e) {
            ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.fail(e.getCause().getMessage()))));
            throw new ServiceException(e.getMessage());
        }
        try {
            if (ObjectUtil.isNull(map.get("msg_id"))) throw new ServiceException("");
            String response = JSON.toJSONString(AjaxResult.success());
            switch (Integer.parseInt(map.get("msg_id").toString())) {
                // 所有用户本局比赛的结果
                case 104:
                    log.info("所有用户本局比赛的结果请求：msg_id 104 ---- 请求参数：game={}", map.get("game"));
                    gameAbstractHandler.gameResultRecord(map.get("game"));
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(response));
                    log.info("所有用户本局比赛的结果请求成功：msg_id 104 ---- 返回结果：{}", response);
                    break;
                // 用户下注
                case 100:
                    log.info("用户下注请求：msg_id 100 ---- 请求参数：data={},game={}", map.get("data"), map.get("game"));
                    response = JSON.toJSONString(AjaxResult.success(Map.of("isSuccess", gameAbstractHandler.userBetting(map.get("data"), map.get("game")))));
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(response));
                    log.info("用户下注请求成功：msg_id 100 ---- 返回结果：{}", response);
                    break;
                // 单个用户对局结果
                case 102:
                    log.info("单个用户对局结果请求：msg_id 102 ---- 请求参数：data={},game={}", map.get("data"), map.get("game"));
                    gameAbstractHandler.userResultRecord(map.get("data"), map.get("game"));
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(response));
                    log.info("单个用户对局结果请求成功：msg_id 102 ---- 返回结果：{}", response);
                    break;
                // 用户登录
                case 106:
                    log.info("登录请求：msg_id 106 ---- 请求参数：data={},game={}", map.get("data"), map.get("game"));
                    // 验证用户是否已经登录
                    boolean isLogin = gameAbstractHandler.loginIn(map.get("data"));
                    // 根据返回的状态组装response数据并返回
                    response = JSON.toJSONString(isLogin ? AjaxResult.success(Map.of("isLogin", true)) : AjaxResult.fail("10003"));
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(response));
                    log.info("登录请求成功：msg_id 106 ---- 返回结果：{}", response);
                    break;
                // 用户退出登录
                case 107:
                    gameAbstractHandler.loginOut();
                    break;
                default:
                    throw new ServiceException("10005");
            }
        } catch (Exception e) {
            log.error("WebSocket请求失败，请求参数={}", text);
            ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.fail(e.getMessage()))));
        }
    }

    /**
     * map转对象
     *
     * @param map
     * @param objectClass
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T mapToObject(Map<String, Object> map, Class<T> objectClass) throws Exception {
        T object = objectClass.newInstance();
        Field[] fields = objectClass.getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            if (map.containsKey(fieldName)) {
                field.setAccessible(true); // 使私有字段可访问
                field.set(object, map.get(fieldName));
            }
        }
        return object;
    }

}
